<?php
/**
 * Copyright (C) 2013 Pablo Sepúlveda P. <psep.pentauc@gmail.com>
 * 
 * This file is part of gAbstract.
 * WarpIT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * gAbstract is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with gAbstract.  If not, see <http://www.gnu.org/licenses/>.
 */

require_once 'AbstractConnect.php';

/**
 * Esta clase produce la abstracción de base de datos
 * con las transacciones.
 * 
 * @author psep
 * @version 1.0
 * @package gAbstract
 * @copyright Copyright (c) 2013 Pablo Sepúlveda P.
 * @license GNU GPLv3 or later
 * @link http://www.psep.cl
 */
class DataBase extends AbstractConnect {
	
	/**
	 * Método constructor de la clase, en la que 
	 * cargan los atributos abstractos para
	 * las instancias de conexión.
	 * 
	 * @param Integer $dbType
	 * @param String $dbHost
	 * @param String $dbPort
	 * @param String $dbName
	 * @param String $dbUser
	 * @param String $dbPass
	 */
	function __construct($dbType, $dbHost, $dbPort, $dbName, $dbUser, $dbPass) {
		$this->driver	= $dbType;
		$this->host		= $dbHost;
		$this->port		= $dbPort;
		$this->db		= $dbName;
		$this->user		= $dbUser;
		$this->password	= $dbPass;
	}
	
	/**
	 * Método que ejecuta una query construida previamente
	 * en el objeto de tipo QueryBuilder y que retorna el
	 * resultado en un data Array.
	 * 
	 * @param QueryBuilder Object
	 * @return dataArray
	 */
	public function exeSelect(\QueryBuilder $queryBuilder){
		$con	= null;
		$stm 	= null;
		$res	= array();
		
		try{
			$con = $this->loadConnection();
			$stm = $con->prepare($queryBuilder->getQuery());
			$size= $queryBuilder->getParameters()->size();
			
			for($i = 0; $i < $size; $i++){
				$parameter = $queryBuilder->getParameters()->get($i);
				
				if($parameter->getObjParam() == null){
					$stm->bindParam($i+1, $parameter->getValue());
				}else{
					$stm->bindParam($i+1, $parameter->getValue(), $parameter->getObjParam());
				}
			}
			
			$stm->setFetchMode(PDO::FETCH_OBJ);
			$stm->execute();
			
			while ($rs = $stm->fetch()) {
				$res[] = $rs;
			}
			
		}catch(PDOException $e){
			echo $e->getMessage();
		}
		
		$this->closeAll($con, $stm);
		
		return $res;
	}
	
	/**
	 * Método que ejecuta el 'CUD' (Create - Update - Delete).
	 * Las transacciones (commit-rollback) vienen activas por defecto.
	 * Se itera la lista de objetos para realizar la transacción,
	 * retornando un true si esta fue exitosa y un false si hay error.
	 * 
	 * @param QueryBuilder Object.
	 * @param array (list's objects)
	 * @return boolean
	 */
	public function executeCUD(\QueryBuilder $queryBuilder, $list){
		$con	= null;
		$flag	= false;
		
		try{
			$con = $this->loadConnection();
			$con->beginTransaction();
			$exec= $this->exeMain($queryBuilder, $list, $con);
			
			if(!$exec){
				$con->rollBack();
			}else{
				$con->commit();
				$flag = true;
			}

		}catch(PDOException $e){
			echo $e->getMessage();
		}
		
		$this->closeAll($con, null);
		
		return $flag;
	}
	
	/**
	 * Método que "resetea" una tabla mediante Truncate.
	 * Verificar si su DB soporta la instrucción.
	 * 
	 * @param String (nombre de la tabla)
	 * @return boolean validation
	 */
	public function resetTable($tableName){
		$con = null;
		$stm = null;
		$res = false;
		$sql = null;
		
		try{
			$sql = new StringBuilder();
			$sql->append("TRUNCATE ");
			$sql->append($tableName);
			$con = $this->loadConnection();
			$stm = $con->prepare($sql->toString());
			$stm->execute();
			$res = true;

		}catch(PDOException $e){
			echo $e->getMessage();
		}
		
		$this->closeAll($con, $stm);
		
		return $res;
	}
	
	/**
	 * Método que produce la iteración de la lista de objetos y
	 * retorna un true en caso exitoso o false en caso de error.
	 * 
	 * @param QueryBuilder Object.
	 * @param array (list's object)
	 * @param PDO::Connection Object
	 * @return boolean
	 */
	private function exeMain(\QueryBuilder $queryBuilder, $list, \PDO $con){
		$stm	= null;
		$bFlag	= false;
		
		try{
			foreach ($list as $object) {
				$bool = $this->execute($queryBuilder, $object, $con);
				
				if(!$bool){
					return false;
				}
			}
			
			$bFlag = true;

		}catch(PDOException $e){
			echo $e->getMessage();
		}
		
		return $bFlag;
	}
	
	/**
	 * Método que hace la ejecución de Insert, Update o Delete según
	 * sea la opción y retorna un boolean de validación.
	 * 
	 * @param QueryBuilder Object
	 * @param Object
	 * @param PDO::Connection Object
	 * @return boolean
	 */
	private function execute(\QueryBuilder $queryBuilder, $object, \PDO $con){
		$bFlag	= false;
		$stm	= null;
		$data	= array();
		
		try{
			switch ($queryBuilder->getOption()) {
				case 2: $data= $queryBuilder->getUpdateDefault($object); break;
				case 3: $data= $queryBuilder->getInsert($object); break;
				case 4: $data= $queryBuilder->getDeleteDefault($object); break;
				default: return false; break;
			}
			
			if(count($data) > 0){
				$stm = $con->prepare($data[0]);
				$size= count($data[1]);
				// Generación del BindParam (PDO::Statement)
				for($i = 0; $i < $size; $i++){
					$stm->bindParam($i+1, $data[1][$i]);
				}
				
				if($stm != null){
					$stm->execute();
					$bFlag = true;
				}
				
			}

		}catch(PDOException $e){
			echo $e->getMessage();
		}
		
		$this->closeAll(null, $stm);
		
		return $bFlag;
	}
	
}

?>